/*
 * Copyright (c) 2014-2017, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 *  ======== doodad.c ========
 */

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

/* #include <xdc/std.h> */
/* #include <xdc/runtime/Log.h> */

#include <ti/hap/HAPAcc.h>
#include "doodad.h"

#define MAXSTRLEN 32

static HAPEngine_SrvStatus setOn(unsigned int aId,
    HAPEngine_CDescPtr cDesc, bool value);
static HAPEngine_SrvStatus getOn(unsigned int aId,
    HAPEngine_CDescPtr cDesc, bool *pvalue);
static HAPEngine_SrvStatus setInt(unsigned int aId,
    HAPEngine_CDescPtr cDesc, int value);
static HAPEngine_SrvStatus getInt(unsigned int aId,
    HAPEngine_CDescPtr cDesc, int *pvalue);
static HAPEngine_SrvStatus setBool(unsigned int aId,
    HAPEngine_CDescPtr cDesc, bool value);
static HAPEngine_SrvStatus getBool(unsigned int aId,
    HAPEngine_CDescPtr cDesc, bool *pvalue);
static HAPEngine_SrvStatus setString(unsigned int aId,
    HAPEngine_CDescPtr cDesc, char *value);
static HAPEngine_SrvStatus getString(unsigned int aId,
    HAPEngine_CDescPtr cDesc, int size, char *pvalue);
static HAPEngine_SrvStatus setFloat(unsigned int aId,
    HAPEngine_CDescPtr cDesc, float value);
static HAPEngine_SrvStatus getFloat(unsigned int aId,
    HAPEngine_CDescPtr cDesc, float *pvalue);

/*
 * Characteristic Description containing an 'on' Characteristic and each of
 * the four custom Characteristics defined above.
 */
const HAPEngine_CharacteristicDesc doodadCharDescs[] = {
    { HAPEngine_C_ON, DOODAD_ON_IID,
        HAPEngine_CPERM_R | HAPEngine_CPERM_W | HAPEngine_CPERM_E |
        HAPEngine_CPERM_NC_E, HAPEngine_CFORMAT_BOOL, HAPEngine_CCS_NONE, NULL,
        { .boolFxns = { setOn, getOn } }, HAPEngine_CUNIT_UNITLESS },

    { Doodad_C_INTUUID, DOODAD_INT_IID, HAPEngine_CPERM_R | HAPEngine_CPERM_W,
        HAPEngine_CFORMAT_INT, HAPEngine_CCS_INT(0, 10, 1), NULL,
        { .integerFxns = { setInt, getInt } }, HAPEngine_CUNIT_UNITLESS },
    { Doodad_C_FLOATUUID, DOODAD_FLOAT_IID,
        HAPEngine_CPERM_R | HAPEngine_CPERM_W,
        HAPEngine_CFORMAT_FLOAT, HAPEngine_CCS_FLOAT(0.0, 10.2, 0.2), NULL,
        { .floatFxns = { setFloat, getFloat } }, HAPEngine_CUNIT_UNITLESS },
    { Doodad_C_BOOLUUID, DOODAD_BOOL_IID, HAPEngine_CPERM_R | HAPEngine_CPERM_W,
        HAPEngine_CFORMAT_BOOL, HAPEngine_CCS_NONE, NULL,
        { .boolFxns = { setBool, getBool } }, HAPEngine_CUNIT_UNITLESS },
    { Doodad_C_STRINGUUID, DOODAD_STRING_IID,
        HAPEngine_CPERM_R | HAPEngine_CPERM_W | HAPEngine_CPERM_E,
        HAPEngine_CFORMAT_STRING, HAPEngine_CCS_STRING(MAXSTRLEN), NULL,
        { .stringFxns  = { setString, getString } },
        HAPEngine_CUNIT_UNITLESS },
};

/* a custom Service, containing Characteristics defined by doodadCharDescs */
const HAPEngine_ServiceDesc doodadServiceDesc = {
    Doodad_S_DOODADUUID,
    DOODAD_SERVICE_IID,
    true,   /* enable service-wide lock */
    HAPEngine_SPROP_PRIMARY, DOODAD_SERVICE_SIG_IID,
    HAPEngine_SLINKED_NONE, NULL,
    sizeof(doodadCharDescs)/sizeof(doodadCharDescs[0]),
    (HAPEngine_CharacteristicDesc *)doodadCharDescs
};

/* a local type/variable to hold context for the custom Service */
typedef struct doodad_Object {
    bool curOn;
    int curInt;
    float curFloat;
    bool curBool;
    char curString[MAXSTRLEN + 1];
} doodad_Object;

static doodad_Object doodad_instance = {0};

static HAPEngine_SrvStatus setOn(unsigned int aId,
    HAPEngine_CDescPtr cDesc, bool value)
{
    HAPEngine_SrvStatus result = (value == doodad_instance.curOn) ?
        HAPEngine_SrvStatus_EOKNOCHANGE : HAPEngine_SrvStatus_EOK;

    doodad_instance.curOn = value;

/*  Log_info3("doodad setOn %d (%d, 0x%x)", aId, value, result); */

    return (result);
}

static HAPEngine_SrvStatus getOn(unsigned int aId,
    HAPEngine_CDescPtr cDesc, bool *pvalue)
{
    *pvalue = doodad_instance.curOn;
/*  Log_info2("doodad getOn %d (%d)", aId, *pvalue); */
    return (HAPEngine_SrvStatus_EOK);
}

static HAPEngine_SrvStatus setInt(unsigned int aId,
    HAPEngine_CDescPtr cDesc, int value)
{
    HAPEngine_SrvStatus result = (value == doodad_instance.curInt) ?
        HAPEngine_SrvStatus_EOKNOCHANGE : HAPEngine_SrvStatus_EOK;

    doodad_instance.curInt = value;
/*  Log_info3("doodad setInt %d (%d, 0x%x)", aId, value, result); */
    return (result);
}

static HAPEngine_SrvStatus getInt(unsigned int aId,
    HAPEngine_CDescPtr cDesc, int *pvalue)
{
    *pvalue = doodad_instance.curInt;

/*  Log_info2("doodad getInt %d (%d)", aId, *pvalue); */

    return (HAPEngine_SrvStatus_EOK);
}

static HAPEngine_SrvStatus setBool(unsigned int aId,
    HAPEngine_CDescPtr cDesc, bool value)
{
    HAPEngine_SrvStatus result = (value == doodad_instance.curBool) ?
        HAPEngine_SrvStatus_EOKNOCHANGE : HAPEngine_SrvStatus_EOK;

    doodad_instance.curBool = value;

/*  Log_info3("doodad setBool %d (%d, 0x%x)", aId, value, result); */

    return (result);
}

static HAPEngine_SrvStatus getBool(unsigned int aId,
    HAPEngine_CDescPtr cDesc, bool *pvalue)
{
    *pvalue = doodad_instance.curBool;

/*  Log_info2("doodad getBool %d (%d)", aId, *pvalue); */

    return (HAPEngine_SrvStatus_EOK);
}

static HAPEngine_SrvStatus setString(unsigned int aId,
    HAPEngine_CDescPtr cDesc, char *value)
{
    strncpy(doodad_instance.curString, value, MAXSTRLEN + 1);

    return (HAPEngine_SrvStatus_EOK);
}

static HAPEngine_SrvStatus getString(unsigned int aId,
    HAPEngine_CDescPtr cDesc, int size, char *pvalue)
{
    strncpy(pvalue, doodad_instance.curString, size);

    return (HAPEngine_SrvStatus_EOK);
}

static HAPEngine_SrvStatus setFloat(unsigned int aId,
    HAPEngine_CDescPtr cDesc, float value)
{
    HAPEngine_SrvStatus result = (value == doodad_instance.curFloat) ?
        HAPEngine_SrvStatus_EOKNOCHANGE : HAPEngine_SrvStatus_EOK;

    doodad_instance.curFloat = value;

    return (result);
}

static HAPEngine_SrvStatus getFloat(unsigned int aId,
    HAPEngine_CDescPtr cDesc, float *pvalue)
{
    *pvalue = doodad_instance.curFloat;

    return (HAPEngine_SrvStatus_EOK);
}
